﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Aquarinum.Base.Infrastructure.Ioc;

namespace Aquarinum.Base.Infrastructure.WebSocket.MessageHandler
{
    /// <summary>
    ///     消息处理策略Mapper
    /// </summary>
    public class MessageHandleStrategyFactory
    {
        private readonly ConcurrentDictionary<string, IList<Tuple<int, Type>>> _strategyCache =
            new ConcurrentDictionary<string, IList<Tuple<int, Type>>>();

        private readonly ConcurrentDictionary<string, IList<Type>> _strategyMap;

        /// <summary>
        ///     注册消息类型的处理策略
        /// </summary>
        /// <param name="type">消息类型</param>
        /// <param name="strategyType">策略ClassType</param>
        /// <param name="enumLifetimeScope"></param>
        public void Register(string type, Type strategyType,
            EnumLifetimeScope enumLifetimeScope = EnumLifetimeScope.InstancePerDependency)
        {
            if (_strategyMap.ContainsKey(type))
            {
                var list = _strategyMap[type];
                list.Add(strategyType);
            }
            else
            {
                _strategyMap.TryAdd(type, new List<Type> {strategyType});
            }

            AquainumContainer.Register(strategyType, strategyType, EnumLifetimeScope.InstancePerDependency);
        }

        /// <summary>
        ///     注册消息类型的处理策略
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type">消息类型</param>
        /// <param name="enumLifetimeScope"></param>
        public void Register<T>(string type,
            EnumLifetimeScope enumLifetimeScope = EnumLifetimeScope.InstancePerDependency)
            where T : MessageHandleStrategyBase
        {
            Register(type, typeof(T), enumLifetimeScope);
        }

        /// <summary>
        ///     自动注册
        /// </summary>
        public void AutoRegisterAllStrategys()
        {
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();

            foreach (var assemblie in assemblies)
            {
                var messageHandleStrategyTypes =
                    assemblie.GetTypes().Where(x =>
                        x.GetInterfaces().Any(y => y.Name == typeof(IMessageHandleStrategy).Name) && x.IsClass);

                foreach (var strategyType in messageHandleStrategyTypes)
                {
                    var propertyAttribute = (HandlerPropertyAttribute)
                        strategyType.GetCustomAttributes(typeof(HandlerPropertyAttribute), false).FirstOrDefault();
                    if (propertyAttribute != null && !string.IsNullOrEmpty(propertyAttribute.MessageType))
                        Register(propertyAttribute.MessageType, strategyType);
                    else
                        Register(strategyType.Name.ToLower().Replace("messagehandlestrategy", string.Empty),
                            strategyType); //此处约定由于配置，所有策略类型命名规则为 ：消息类型+MessageHandleStrategy
                }
            }
        }


        /// <summary>
        ///     获取策略实例
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public IList<IMessageHandleStrategy> GetStrategyInstance(string type)
        {
            IList<IMessageHandleStrategy> result = new List<IMessageHandleStrategy>();
            var cached = _strategyCache.TryGetValue(type, out var strategytypecache);

            if (cached && strategytypecache != null)
            {
                foreach (var typeTuple in strategytypecache.OrderBy(x => x.Item1))

                    if (AquainumContainer.Resolve(typeTuple.Item2) is IMessageHandleStrategy instance)
                        result.Add(instance);
            }
            else
            {
                var hasRegistered = _strategyMap.TryGetValue(type, out var strategytypelist);

                if (hasRegistered && strategytypelist != null)
                {
                    var typeTuples = new List<Tuple<int, Type>>();
                    foreach (var strategytype in strategytypelist)
                    {
                        var order = (strategytype
                                        .GetCustomAttributes(typeof(HandlerPropertyAttribute), false)
                                        .FirstOrDefault() as HandlerPropertyAttribute)?.HandlerOrder ?? 0;


                        typeTuples.Add(new Tuple<int, Type>(order, strategytype));
                    }

                    _strategyCache.TryAdd(type, typeTuples);

                    foreach (var typeTuple in typeTuples.OrderBy(x => x.Item1))

                        if (AquainumContainer.Resolve(typeTuple.Item2) is IMessageHandleStrategy instance)
                            result.Add(instance);
                }
            }

            return result;
        }

        #region 单例封装

        private static MessageHandleStrategyFactory _instance;
        private static readonly object Instancelocker = new object();


        private MessageHandleStrategyFactory()
        {
            _strategyMap = new ConcurrentDictionary<string, IList<Type>>();
        }

        /// <summary>
        ///     单例实例
        /// </summary>
        /// <returns></returns>
        public static MessageHandleStrategyFactory GetInstance()
        {
            //没有第一重 instance == null 的话，每一次有线程进入 GetInstance()时，均会执行锁定操作来实现线程同步，
            //非常耗费性能 增加第一重instance ==null 成立时的情况下执行一次锁定以实现线程同步
            if (_instance == null)
                lock (Instancelocker)
                {
                    //Double-Check Locking 双重检查锁定
                    if (_instance == null) _instance = new MessageHandleStrategyFactory();
                }

            return _instance;
        }

        #endregion
    }
}